package com.songhq.data.log;

import feign.Logger;
import feign.Logger.Level;
import feign.Request;
import feign.Response;
import feign.Response.Body;
import feign.Response.Builder;
import feign.Util;
import feign.slf4j.Slf4jLogger;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.slf4j.LoggerFactory;

import com.songhq.data.log.util.LogUtil;

public class FeignLog extends Slf4jLogger
{
  private static final String BODYLENGTH = "bodyLength:";
  private static final String SRVCODE = "srv_code";
  private final org.slf4j.Logger logger;

  public FeignLog()
  {
    this(feign.Logger.class);
  }

  public FeignLog(Class<?> clazz) {
    this(LoggerFactory.getLogger(clazz));
  }

  public FeignLog(String name) {
    this(LoggerFactory.getLogger(name));
  }

  FeignLog(org.slf4j.Logger logger) {
    this.logger = logger;
  }

  protected void logRequest(String configKey, Logger.Level logLevel, Request request)
  {
    String common = LogUtil.feignComm(configKey, 100, 0L);
    StringBuilder logstr = new StringBuilder(common);
    logstr.append("|").append(0);
    logstr.append("|").append(0);
    logstr.append("|").append(100);
    logstr.append("|").append(LogType.REQUEST);

    logstr.append("|").append("^").append(request.method()).append("^").append(request.url());

    StringBuilder hstr = new StringBuilder();
    if (logLevel.ordinal() >= Logger.Level.HEADERS.ordinal()) {
      for (Iterator localIterator1 = request.headers().keySet().iterator(); localIterator1.hasNext(); ) {String field = (String)localIterator1.next();
        for (String value : Util.valuesOrEmpty(request.headers(), field))
          hstr.append("^").append(field).append(":").append(value);
      }
      String field;
      logstr.append(hstr);

      int bodyLength = 0;
      if (request.body() != null) {
        bodyLength = request.body().length;
        if (logLevel.ordinal() >= Logger.Level.FULL.ordinal()) {
          String bodyText = request.charset() != null ? new String(request.body(), request.charset()) : null;
          logstr.append("^").append(bodyText != null ? bodyText : "Binary data");
        }
      }
      logstr.append("^").append("bodyLength:").append(bodyLength);
      this.logger.info(logstr.toString());
    }
  }

  protected Response logAndRebufferResponse(String configKey, Logger.Level logLevel, Response response, long elapsedTime) throws IOException
  {
    String reason = (response.reason() != null) && (logLevel.compareTo(Logger.Level.NONE) > 0) ? " " + response.reason() : "";
    int status = response.status();

    String common = LogUtil.feignComm(configKey, status, elapsedTime);
    StringBuilder logstr = new StringBuilder(common);
    int srvCode = 100;
    if (logLevel.ordinal() >= Logger.Level.HEADERS.ordinal()) {
      StringBuffer fullH = new StringBuffer();
      long useTime = 0L;
      for (Iterator localIterator1 = response.headers().keySet().iterator(); localIterator1.hasNext(); ) { String field = (String)localIterator1.next();
        for (String value : Util.valuesOrEmpty(response.headers(), field)) {
          if (field.equalsIgnoreCase("P_USETIME"))
            useTime = Long.parseLong(value);
          else if ((field.equalsIgnoreCase("srv_code")) && 
            (null != value) && (!"".equals(value))) {
            srvCode = Integer.parseInt(value);
          }

          fullH.append("^").append(field).append(":").append(value);
        }
      }
      logstr.append("|").append(useTime);
      logstr.append("|").append(elapsedTime - useTime);

      logstr.append("|").append(srvCode);
      logstr.append("|").append(LogType.RESPONSE);
      logstr.append("|").append("^").append(reason);
      logstr.append(fullH);

      int bodyLength = 0;
      if ((response.body() != null) && (status != 204) && (status != 205)) {
        if (logLevel.ordinal() >= Logger.Level.FULL.ordinal());
        byte[] bodyData = Util.toByteArray(response.body().asInputStream());
        bodyLength = bodyData.length;

        if ((logLevel.ordinal() >= Logger.Level.FULL.ordinal()) && (bodyLength > 0))
        {
          String bodystr = Util.decodeOrDefault(bodyData, Util.UTF_8, "Binary data");

          logstr.append("^").append(bodystr);
        }
        logstr.append("^").append("bodyLength:").append(bodyLength);

        this.logger.info(logstr.toString());
        return response.toBuilder().body(bodyData).build();
      }
      logstr.append("^").append("bodyLength:").append(bodyLength);

      this.logger.info(logstr.toString());
    }

    return response;
  }

  protected void log(String configKey, String format, Object[] args)
  {
    this.logger.debug(String.format(methodTag(configKey) + format, args));
  }

  static enum LogType {
    RESPONSE, REQUEST;
  }
}